package com.dreamlike.demo.HttpUtil.Core.Generator;

import com.dreamlike.demo.HttpUtil.Core.HttpDefinition;
import com.dreamlike.demo.HttpUtil.Core.ReuqestBodyHandler.JsonRequestBodyHandler;
import com.dreamlike.demo.HttpUtil.Core.ReuqestBodyHandler.RequestBodyHandler;
import com.dreamlike.demo.HttpUtil.Core.ReuqestBodyHandler.UrlencodedRequestBodyHandler;
import com.dreamlike.demo.HttpUtil.Enum.ContentType;
import com.dreamlike.demo.HttpUtil.Enum.RequestMethod;
import com.dreamlike.demo.HttpUtil.Core.ReuqestBodyHandler.StringRequestBodyHandler;
import lombok.Setter;

import java.net.URI;
import java.net.http.HttpRequest;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

@Setter
public class HttpRequestGenerator {
    /**
     * 非线程安全，建议在配置阶段修改，正式运行时不允许修改
     * 以上只做约定
     */
    private Map<String, RequestBodyHandler> typeTransBodyMap;


    public HttpRequestGenerator(){
        typeTransBodyMap = new HashMap<>();
        typeTransBodyMap.put(ContentType.APPLICATION_JSON,new JsonRequestBodyHandler());
        typeTransBodyMap.put(ContentType.APPLICATION_FORM_URLENCODED,new UrlencodedRequestBodyHandler());
    }

    public HttpRequestGenerator(JsonRequestBodyHandler.JsonGenerator jsonGenerator) {
        typeTransBodyMap = new HashMap<>();
        typeTransBodyMap.put(ContentType.APPLICATION_JSON,new JsonRequestBodyHandler(jsonGenerator));
        typeTransBodyMap.put(ContentType.APPLICATION_FORM_URLENCODED,new UrlencodedRequestBodyHandler());
    }

    public HttpRequestGenerator(Map<String, RequestBodyHandler> other) {
        this();
        typeTransBodyMap.putAll(other);
    }
    public HttpRequestGenerator(Map<String, RequestBodyHandler> other, JsonRequestBodyHandler.JsonGenerator jsonGenerator) {
        this(jsonGenerator);
        typeTransBodyMap.putAll(other);
    }
    public void addNewTransHandler(RequestBodyHandler requestBodyHandler, String contentType){
        typeTransBodyMap.putIfAbsent(contentType, requestBodyHandler);
    }
    public void addOrUpdateTransHandler(RequestBodyHandler requestBodyHandler, String contentType){
        typeTransBodyMap.put(contentType, requestBodyHandler);
    }


    public HttpRequest generate(HttpDefinition httpDefinition, Object[] args){
        HttpRequest now = null;
        switch (httpDefinition.getRequestMethod()){
            case GET:
            case DELETE: {
                now = produceUrlRequest(args, httpDefinition);
                break;
            }

            case POST:
            case PUT:{
                now = produceStringBodyRequest(args, httpDefinition);
                break;
            }
        }
        return now;
    }




    private HttpRequest produceStringBodyRequest(Object[] args, HttpDefinition httpDefinition){
        RequestBodyHandler requestBodyHandler = typeTransBodyMap.get(httpDefinition.getRequestContentType());
        if(!(requestBodyHandler instanceof StringRequestBodyHandler)){
            throw new RuntimeException(requestBodyHandler.getClass()+"不为TransStringBody子类");
        }


        HttpRequest.Builder builder = HttpRequest.newBuilder()
                .uri(URI.create(httpDefinition.getBaseUri()));

        if(httpDefinition.getRequestMethod().equals(RequestMethod.POST)){
            builder.POST(HttpRequest.BodyPublishers.ofString(((StringRequestBodyHandler) requestBodyHandler).trans(httpDefinition,args)));
        }else {
            builder.PUT(HttpRequest.BodyPublishers.ofString(((StringRequestBodyHandler) requestBodyHandler).trans(httpDefinition,args)));
        }

        setHeadersAndVersionAndTimeout(args, httpDefinition,builder);

        return builder.build();
    }

    private HttpRequest produceUrlRequest(Object[] args, HttpDefinition httpDefinition){
        String urlWithParam = new StringBuilder(httpDefinition.getBaseUri())
                .append("?")
                .append(typeTransBodyMap.get(ContentType.APPLICATION_FORM_URLENCODED).trans(httpDefinition, args))
                .toString();
        HttpRequest.Builder builder = HttpRequest.newBuilder()
                .uri(URI.create(urlWithParam));
        setHeadersAndVersionAndTimeout(args,httpDefinition, builder);
        if (httpDefinition.getRequestMethod().equals(RequestMethod.GET)){
            builder.GET();
        }else {
            builder.DELETE();
        }
        return builder.build();
    }
    private void setHeadersAndVersionAndTimeout(Object[] args, HttpDefinition httpDefinition, HttpRequest.Builder builder) {
        builder.setHeader("content-type", httpDefinition.getRequestContentType());
        httpDefinition.getHeadersRecord()
                .forEach((index,key) -> builder.setHeader(key, args[index].toString()));
        builder.timeout(Duration.ofSeconds(httpDefinition.getTimeoutSeconds()))
                .version(httpDefinition.getVersion());
    }


}
